﻿namespace Cellfish.Toolbox.Tasks
{
    using System;

    /// <summary>
    /// Provides an IProgress&lt;T&gt; that invokes callbacks for each reported progress value synchronously.
    /// </summary>
    /// <typeparam name="T">Specifies the type of the progress report value.</typeparam>
    public class ProgressSimple<T> : IProgress<T>
    {
        private readonly Action<T> handler;

        /// <summary>
        /// Initializes a new instance of the <see cref="ProgressSimple{T}"/> class.
        /// </summary>
        /// <param name="handler">A handler to invoke for each reported progress value.</param>
        /// <exception cref="System.ArgumentNullException">If handler is null.</exception>
        public ProgressSimple(Action<T> handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }

            this.handler = handler;
        }

        /// <summary>
        /// Reports a progress update.
        /// </summary>
        /// <param name="value">The value of the updated progress.</param>
        public virtual void Report(T value)
        {
            this.handler(value);
        }
    }

    /// <summary>
    /// Provides an IProgress&lt;T&gt; that invokes callbacks for each reported progress value synchronously.
    /// If any progress report throws an exception that exception is caught and stored.
    /// </summary>
    /// <typeparam name="T">Specifies the type of the progress report value.</typeparam>
    public class ProgressSafe<T> : ProgressSimple<T>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ProgressSimple{T}"/> class.
        /// </summary>
        /// <param name="handler">A handler to invoke for each reported progress value.</param>
        /// <exception cref="System.ArgumentNullException">If handler is null.</exception>
        public ProgressSafe(Action<T> handler)
            : base(handler)
        {
        }

        /// <summary>
        /// Gets the last error.
        /// </summary>
        /// <value>
        /// The last exception caught when reporting progress.
        /// </value>
        public Exception LastError { get; private set; }

        /// <summary>
        /// Reports the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void Report(T value)
        {
            try
            {
                base.Report(value);
            }
            catch (Exception ex)
            {
                this.LastError = ex;
            }
        }
    }
}
